package com.yunduo.world.config;

import com.yunduo.world.entity.EntityInfo;
import com.yunduo.world.handler.ClientHeartHandler;
import com.yunduo.world.handler.WorldServerHandler;
import com.yunduo.world.handler.encoder.DecodeUnPack;
import com.yunduo.world.handler.encoder.EncoderPack;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.string.LineEncoder;
import io.netty.handler.codec.string.LineSeparator;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

/**
 * netty配置信息
 */
@Slf4j
@Configuration
public class NettyConfig {
    @Value("${world.port}")
    private int port;
    @Value("${world.threadSize}")
    private int threadSize;
    @Value("${world.waitSize}")
    private int waitSize;

    private ServerBootstrap bootstrap;
    private NioEventLoopGroup bossGroup;
    private NioEventLoopGroup workerGroup;
    private ChannelFuture channelFuture;
    // 注入netty引导组件
    @Bean
    public ServerBootstrap serverBootstrap () {
        bossGroup = new NioEventLoopGroup(threadSize);
        workerGroup = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup) // 设置两个线程组
                .channel(NioServerSocketChannel.class) // 使用NioServerSocketChannel作为服务器的通道实现
                .option(ChannelOption.SO_BACKLOG, waitSize) // 设置线程队列等待连接个数
                .childOption(ChannelOption.SO_KEEPALIVE, true) // 设置保持活动连接状态
                .childHandler(pipeLineHandlerList()); // 为WorkerGroup的 EventLoop对应的管道设置处理
        bootstrap = serverBootstrap;
        return serverBootstrap;
    }

    /**
     * 通道对象初始化
     *   配置编码解码器
     *   配置任务执行类
     *   配置心跳处理类
     */
    public ChannelInitializer<SocketChannel> pipeLineHandlerList(){
        return new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                ChannelPipeline pipeline = socketChannel.pipeline();
//                pipeline.addLast("encoderPack",new LineEncoder(LineSeparator.DEFAULT, CharsetUtil.UTF_8));
                pipeline.addLast("decoderUnPack",new DecodeUnPack());
                pipeline.addLast("decoder",new ProtobufDecoder(EntityInfo.Entity.getDefaultInstance()));
                pipeline.addLast("encoderPack",new EncoderPack());
                pipeline.addLast("encoder", new ProtobufEncoder());
                pipeline.addLast("exec",new WorldServerHandler());
                pipeline.addLast(new IdleStateHandler(1800, 1800, 1800, TimeUnit.SECONDS));
                pipeline.addLast("heartListen",new ClientHeartHandler());
            }
        };
    }

    // 启动
    public void run() throws InterruptedException {
            channelFuture = bootstrap.bind(port).sync();
    }

    // 优雅关闭
    public void closeGroup(){
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }

    // 通道关闭后执行的操作
    public void channelCloseAfter(){
        channelFuture.channel().closeFuture().addListener(future -> {
           // TO-DO
        });
    }
}
